package lsp

var arraySchemaMessage = map[string]string{
	"required": "{{#label}} is not allowed to be empty",
	"length":   "{{#label}} must contain {{#limit}} items",
	"max":      "{{#label}} must contain less than or equal to {{#limit}} items",
	"min":      "{{#label}} must contain at least {{#limit}} items",
}

func NewArray() *arraySchema {
	return &arraySchema{
		rules: map[string]func(value []interface{}) error{},
		anySchema: anySchema{
			label:   "value",
			message: arraySchemaMessage,
		},
	}
}

type arraySchema struct {
	anySchema
	rules map[string]func(value []interface{}) error
}

func (schema *arraySchema) addRule(method string, hook func(value []interface{}) error) *arraySchema {
	schema.rules[method] = hook
	return schema
}

// Validate a value using the schema.
func (schema *arraySchema) Validate(value []interface{}) error {
	for _, hook := range schema.rules {
		if err := hook(value); nil != err {
			return err
		}
	}
	return nil
}

// Custom adds a custom validation function.
func (schema *arraySchema) Custom(fn func(value []interface{}) error) *arraySchema {
	return schema.addRule("custom", fn)
}

// Label overrides the key name in error messages.
func (schema *arraySchema) Label(name string) *arraySchema {
	schema.label = name
	return schema
}

// Required requires the array value is not allowed to be empty.
func (schema *arraySchema) Required() *arraySchema {
	return schema.addRule("required", func(value []interface{}) error {
		if 0 < len(value) {
			return nil
		}
		return schema.error("required", nil)
	})
}

// Length specifies the exact number of items in the array.
func (schema *arraySchema) Length(limit int) *arraySchema {
	return schema.addRule("length", func(value []interface{}) error {
		if len(value) == limit {
			return nil
		}
		return schema.error("length", map[string]interface{}{"limit": limit})
	})
}

// Max specifies the maximum number of items in the array.
func (schema *arraySchema) Max(limit int) *arraySchema {
	return schema.addRule("max", func(value []interface{}) error {
		if len(value) <= limit {
			return nil
		}
		return schema.error("max", map[string]interface{}{"limit": limit})
	})
}

// Min specifies the minimum number of items in the array.
func (schema *arraySchema) Min(limit int) *arraySchema {
	return schema.addRule("min", func(value []interface{}) error {
		if len(value) >= limit {
			return nil
		}
		return schema.error("min", map[string]interface{}{"limit": limit})
	})
}

// EachCustom add validation function for each item.
func (schema arraySchema) EachCustom(fn func(value interface{}) error) *arraySchema {
	return schema.addRule("eachCustom", func(value []interface{}) error {
		for _, val := range value {
			if err := fn(val); nil != err {
				return err
			}
		}
		return nil
	})
}
